%------------------------------------------------------------
% Author: vjache
% Created: 06.11.2009
% Description: TODO: Add description to parse_ttl
%------------------------------------------------------------
-module(parse_ttl).

%------------------------------------------------------------
% Include files
%------------------------------------------------------------
-include("../include/pipe.hrl").
-include("../include/parser.hrl").
%------------------------------------------------------------
% Exported Functions
%------------------------------------------------------------
-export([new/1,
		 open/1,
		 push/2,
		 flush/1,
		 close/1,
		 test/0,
		 test/1]).

-record(m_state,{parent=nil,ctx,triple,next_pipe}).
-record(prefix_state,{parent,entry=#prefix{}}).
-record(skip_state,{parent}).
-record(skip_comment,{parent}).
-record(skip_quotes,{parent,count}).
-record(uri_state,{parent,buff=[]}).
-record(puri_state,{parent,buff=#puri{prefix=[],frag=nil}}).
-record(lit_state,{parent,buff=[],is_multiline=false}).
-record(num_lit_state,{parent,buff=[],type=nil}).
-record(lit_suffix_state,{parent,type=nil,lexeme,buff=[]}).

-define(IS_NODE(Node),Node==subj orelse Node==pred orelse Node==obj).

%------------------------------------------------------------
% API Functions
%------------------------------------------------------------

new(NextPipe) ->
	pipe:pipe_from_module(?MODULE, nil, NextPipe).

open({Parent,NextPipe}) -> %%PipeState
	#m_state{
			 parent=Parent,
			 ctx=[prefix],
			 triple=#triple{},
			 next_pipe=pipe:open(NextPipe)
			}.
%% Skip white spaces 
push(S=#m_state{parent=_,ctx=[Node],triple=_,next_pipe=_},
	 ?NUM) when ?IS_NODE(Node) orelse Node==prefix ->
	#skip_comment{parent=fun(_)-> S end}; 
push(S=#m_state{parent=_,ctx=[Node],triple=_,next_pipe=_},
	 Char) when ?IS_WITE_SPACE(Char) andalso (?IS_NODE(Node) orelse Node==prefix)  ->
	#skip_state{parent=fun(_)-> S end};
%% Handle prefix [prefixID ::= '@prefix' ws+ prefixName? ':' uriref]
push(S=#m_state{parent=_,ctx=[prefix],triple=_,next_pipe=NextPipeState},?DOG) ->
	Ret=fun(Entry)->
				NextPipeState1=pipe:push(NextPipeState,Entry),
				S#m_state{next_pipe=NextPipeState1}
		end,
	#prefix_state{parent=Ret,entry=[]};
push(S=#m_state{parent=_,ctx=[prefix],triple=_,next_pipe=_},Char) ->
	push(S#m_state{ctx=[subj]},Char);
%% Handle nested object
push(S=#m_state{parent=_,ctx=[obj],triple=Trp,next_pipe=NextPipeState},
	 ?SQ_BRA) ->
	Obj=#uri{lexeme=make_ref()},
	Ret=fun(PipeState)->
				S#m_state{ctx=[finish_triple],triple=Trp#triple{o=Obj},next_pipe=PipeState}
		end,
	#m_state{
			 parent=Ret,
			 ctx=[pred],
			 triple=#triple{s=Obj},
			 next_pipe=NextPipeState
			};
%% Extract Node when it is a URI or Prefixed URI
push(S=#m_state{parent=_,ctx=[Node],triple=Trp,next_pipe=_},
	 ?ANG_BRA) when ?IS_NODE(Node) ->
	#uri_state{parent=
				   fun(Uri)-> 
						   case Node of
							   subj ->
								   S#m_state{ctx=[next_node(Node)],triple=Trp#triple{s=Uri}};
							   pred ->
								   S#m_state{ctx=[next_node(Node)],triple=Trp#triple{p=Uri}};
							   obj ->
								   S#m_state{ctx=[finish_triple],triple=Trp#triple{o=Uri}}
						   end
				   end};
%% Handle last ; and . in [...] situation 
push(S=#m_state{parent=Ret,ctx=[pred],triple=Trp,next_pipe=_},
	 ?SQ_KET) when Ret/=nil->
	push(S#m_state{ctx=[finish_triple],triple=Trp#triple{}},?SQ_KET);
push(S=#m_state{parent=Ret,ctx=[subj],triple=Trp,next_pipe=_},
	 ?DOT) when Ret/=nil->
	push(S#m_state{ctx=[finish_triple],triple=Trp#triple{}},?DOT);
push(S=#m_state{parent=_,ctx=[Node],triple=Trp,next_pipe=_},
	 Char) when 
  ?IS_NODE(Node) andalso
	  Char/=?ANG_BRA andalso
	  Char/=?QUOTE andalso
	  ?NOT_WITE_SPACE(Char) andalso
	  (not ?IS_NUM_START(Char)) ->
	push(#puri_state{parent=
				   fun(PUri)-> 
						   case Node of
							   subj ->
								   S#m_state{ctx=[next_node(Node)],triple=Trp#triple{s=PUri}};
							   pred ->
								   S#m_state{ctx=[next_node(Node)],triple=Trp#triple{p=PUri}};
							   obj ->
								   S#m_state{ctx=[finish_triple],triple=Trp#triple{o=PUri}}
						   end
				   end},Char);
%% Extract Object Node when it is Literal
push(S=#m_state{parent=_,ctx=[obj],triple=Trp,next_pipe=_},
	 ?QUOTE) ->
	#lit_state{parent=
				   fun(Lit)-> 
						   S#m_state{ctx=[finish_triple],triple=Trp#triple{o=Lit}}
				   end};
%% Extract Object Node when it is Numerical Literal 
push(S=#m_state{parent=_,ctx=[obj],triple=Trp,next_pipe=_},
	 Char) when ?IS_NUM_START(Char) ->
	push(#num_lit_state{parent=
				   fun(Lit)-> 
						   S#m_state{ctx=[finish_triple],triple=Trp#triple{o=Lit}}
				   end},Char);
%% Extract Finish character
push(S=#m_state{parent=_,ctx=[finish_triple],triple=_,next_pipe=_},
	 Char) when ?IS_WITE_SPACE(Char) ->
	#skip_state{parent=fun(_)-> S end};
push(S=#m_state{parent=_,ctx=[finish_triple],triple=_,next_pipe=_},
	 FinChar) when 
  FinChar==?DOT orelse 
	  FinChar==?SQ_KET orelse 
	  FinChar==?COMMA orelse 
	  FinChar==?SEMI_COLON ->
	triple_finish(S,FinChar);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Skip comment state handling 
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
push(#skip_comment{parent=Ret},?NL) ->
	Ret([]);
push(S=#skip_comment{parent=_},_Char) ->
	S;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Skip state handling
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
push(S=#skip_state{parent=_},Char) when ?IS_WITE_SPACE(Char) ->
	S;
push(#skip_state{parent=Ret},Char) when ?NOT_WITE_SPACE(Char) ->
	D=Ret([]),
%% 	io:format("Here ~p ~p~n",[[Char],D]),
	push(D,Char);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Prefix state handling
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
push(S=#prefix_state{parent=_,entry=[]},$p)->
	S#prefix_state{entry=[$p]};
push(S=#prefix_state{parent=_,entry=[$p]},$r)->
	S#prefix_state{entry=[$r,$p]};
push(S=#prefix_state{parent=_,entry=[$r,$p]},$e)->
	S#prefix_state{entry=[$e,$r,$p]};
push(S=#prefix_state{parent=_,entry=[$e,$r,$p]},$f)->
	S#prefix_state{entry=[$f,$e,$r,$p]};
push(S=#prefix_state{parent=_,entry=[$f,$e,$r,$p]},$i)->
	S#prefix_state{entry=[$i,$f,$e,$r,$p]};
push(S=#prefix_state{parent=_,entry=[$i,$f,$e,$r,$p]},$x)->
	S#prefix_state{entry=[$x,$i,$f,$e,$r,$p]};
push(S=#prefix_state{parent=_,entry=[$x,$i,$f,$e,$r,$p]},Char) when ?IS_WITE_SPACE(Char)->
	S#prefix_state{entry=[$\s,$x,$i,$f,$e,$r,$p]};
push(S=#prefix_state{parent=_,entry=[$\s,$x,$i,$f,$e,$r,$p]},Char) when ?IS_WITE_SPACE(Char)->
	S;
push(S=#prefix_state{parent=_,entry=[$\s,$x,$i,$f,$e,$r,$p]},Char)->
	S#prefix_state{entry=#prefix{name=[Char],uri=nil}};
push(S=#prefix_state{parent=_,entry=#prefix{name=Buff,uri=nil}},?COLON)->
	S#prefix_state{entry=#prefix{name=lists:reverse(Buff),uri=[]}};
push(S=#prefix_state{parent=_,entry=Pfx=#prefix{name=Buff,uri=nil}},Char)->
	S#prefix_state{entry=Pfx#prefix{name=[Char|Buff]}};
push(S=#prefix_state{parent=_,entry=#prefix{name=_,uri=[]}},Char) when ?IS_WITE_SPACE(Char)->
	Ret=fun(_)-> S end,
	#skip_state{parent=Ret};
push(S=#prefix_state{parent=_,entry=Pfx=#prefix{name=_,uri=[]}},?ANG_BRA)->
	Ret=fun(Uri)-> S#prefix_state{entry=Pfx#prefix{uri=Uri}} end,
	#uri_state{parent=Ret};
push(S=#prefix_state{parent=_,entry=#prefix{name=_,uri=#uri{lexeme=_}}},Char) when ?IS_WITE_SPACE(Char)->
	Ret=fun(_)-> S end,
	#skip_state{parent=Ret};
push(#prefix_state{parent=Ret,entry=Pfx=#prefix{name=_,uri=#uri{lexeme=_}}},?DOT)->
	Ret(Pfx);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% URI state handling
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
push(S=#uri_state{parent=_,buff=Buff},Char) when Char/=?ANG_KET andalso ?NOT_WITE_SPACE(Char) ->% Specifiy here bad char class for URI
	S#uri_state{buff=[Char|Buff]};
push(#uri_state{parent=Ret,buff=Buff},?ANG_KET) ->
	Ret(#uri{lexeme=lists:reverse(Buff)});
push(#uri_state{parent=_,buff=Buff},BadChar) ->
	throw({bad_uri,lists:reverse([BadChar|Buff])});
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Prefixed URI state handling
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
push(S=#puri_state{parent=_,buff=#puri{prefix=[],frag=nil}},$a) ->
	S#puri_state{buff=#puri{prefix=[$a],frag=nil}};
push(#puri_state{parent=Ret,buff=#puri{prefix=[$a],frag=nil}},Char) 
  when ?IS_WITE_SPACE(Char) orelse ?IS_TRIPLE_FINISH(Char) ->
	push(Ret(#puri{prefix="rdf",frag="type"}),Char);
push(S=#puri_state{parent=_,buff=#puri{prefix=Pfx,frag=nil}},?COLON) ->
	S#puri_state{buff=#puri{prefix=Pfx,frag=[]}};
push(#puri_state{parent=Ret,buff=#puri{prefix=Pfx,frag=Frag}},Char) 
  when Frag/=nil andalso (?IS_TRIPLE_FINISH(Char)) ->
	push(Ret(#puri{prefix=lists:reverse(Pfx),frag=lists:reverse(Frag)}),Char);
push(S=#puri_state{parent=_,buff=#puri{prefix=Pfx,frag=nil}},Char) when ?NOT_WITE_SPACE(Char) ->
	S#puri_state{buff=#puri{prefix=[Char|Pfx],frag=nil}};
push(S=#puri_state{parent=_,buff=#puri{prefix=Pfx,frag=Frag}},Char) when ?NOT_WITE_SPACE(Char) ->
	S#puri_state{buff=#puri{prefix=Pfx,frag=[Char|Frag]}};
push(#puri_state{parent=_,buff=Buff},Char) ->
	throw({bad_puri,Buff,[Char]});
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Numerical Literal state handling
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
push(S=#num_lit_state{parent=_,buff=[],type=nil},Char)
  when ?IS_NUM_START(Char) ->
	S#num_lit_state{buff=[Char]};
push(S=#num_lit_state{parent=_,buff=Buff,type=_},Char)
  when ?IS_DIGIT(Char) orelse ?IS_SIGN(Char) orelse ?IS_EXP(Char) orelse Char==?DOT ->
	S#num_lit_state{buff=[Char|Buff]};
push(#num_lit_state{parent=Ret,buff=Buff=[_|_],type=_Type},Char)
  when ?IS_TRIPLE_FINISH(Char) ->
	HasExp=lists:any(fun(Ch)-> ?IS_EXP(Ch) end, Buff),
	HasDot=lists:any(fun(Ch)-> Ch==?DOT end, Buff),
	RetSt=case {HasDot,HasExp} of
		{_,true}->
			Ret(#tlit{
					  lexeme=lists:reverse(Buff),
					  type=#puri{prefix="xsd",frag="double"}
					 });
		{false,false}->
			Ret(#tlit{
					  lexeme=lists:reverse(Buff),
					  type=#puri{prefix="xsd",frag="integer"}
					 });
		{true,false}->
			Ret(#tlit{
					  lexeme=lists:reverse(Buff),
					  type=#puri{prefix="xsd",frag="decimal"}
					 })
	end,
	push(RetSt,Char);
	
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Literal state handling: Skip quotes
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 
push(S=#skip_quotes{parent=_,count=Cnt},?QUOTE) ->
	S#skip_quotes{count=Cnt+1};
push(#skip_quotes{parent=Ret,count=Cnt},Char) when Char/=?QUOTE ->
	Ret({Cnt,Char});
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Literal state handling: Lexeme
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
push(S=#lit_state{parent=_,buff=[]},?QUOTE)->
	Ret=fun({3,Char})->
				push(S#lit_state{is_multiline=true},Char);
		   ({2,Char}) -> %%Empty single line literal case
				push(push(S#lit_state{buff=[empty]},?QUOTE),Char);
		   ({Cnt,Char})->
				throw({multi_line_quote_expected,{Cnt,[Char]}})
		end,
	#skip_quotes{parent=Ret,count=2};
push(S=#lit_state{parent=_,buff=[?ESCAPE|Tail],is_multiline=_},?ESCAPE)->
	S#lit_state{buff=[?ESCAPE|Tail]};
push(S=#lit_state{parent=_,buff=[?ESCAPE|Tail],is_multiline=_},?QUOTE)->
	S#lit_state{buff=[?QUOTE|Tail]};
push(#lit_state{parent=Ret,buff=Buff,is_multiline=false},?QUOTE)->
	#lit_suffix_state{
					  parent=Ret,
					  lexeme=lists:reverse(Buff)
					  };
push(#lit_state{parent=Ret,buff=Buff,is_multiline=true},?QUOTE)->
	Ret1=fun({3,Char})->
				push(#lit_suffix_state{
					  parent=Ret,
					  lexeme=lists:reverse(Buff)					 
					  },Char);
		   (Cnt)->
				throw({multi_line_quote_expected,Cnt})
		end,
	#skip_quotes{parent=Ret1,count=1};
push(S=#lit_state{parent=_,buff=Buff,is_multiline=_},Char)->
	S#lit_state{buff=[Char|Buff]};
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Literal state handling: No postfix 
%% (i.e. plain literal) 
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
push(#lit_suffix_state{parent=Ret,type=_,lexeme=Lex,buff=[]},Char) 
  when ?IS_WITE_SPACE(Char) orelse ?IS_TRIPLE_FINISH(Char) ->
	push(Ret(#plit{lexeme=Lex}),Char);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Literal state handling: Language
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
push(S=#lit_suffix_state{parent=_,type=_,lexeme=_,buff=[]},?DOG)->
	S#lit_suffix_state{type=llit,buff=[?DOG]};
push(#lit_suffix_state{parent=Ret,type=llit,lexeme=Lex,buff=Buff},Char) when ?IS_TRIPLE_FINISH(Char)->
	[?DOG|Val]=lists:reverse(Buff),
	push(Ret(#llit{lang=Val,lexeme=Lex}),Char);
push(S=#lit_suffix_state{parent=_,type=llit,lexeme=_,buff=Buff},Char)->
	S#lit_suffix_state{buff=[Char|Buff]};
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Literal state handling: Type : ^^<...> 
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
push(S=#lit_suffix_state{parent=_,type=_,lexeme=_,buff=[]},?UP)->
	S#lit_suffix_state{type=tlit,buff=[?UP]};
push(S=#lit_suffix_state{parent=_,type=tlit,lexeme=_,buff=[?UP]},?UP)->
	S#lit_suffix_state{buff=[?UP,?UP]};
push(#lit_suffix_state{parent=Ret,type=tlit,lexeme=Lex,buff=[?UP,?UP]},?ANG_BRA)->
	Ret1=fun(Uri)->
				 Ret(#tlit{lexeme=Lex,type=Uri})
		 end,
	#uri_state{parent=Ret1};
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Literal state handling: Type : ^^...
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
push(#lit_suffix_state{parent=Ret,type=tlit,lexeme=Lex,buff=[?UP,?UP]},Char) 
  when ?NOT_WITE_SPACE(Char) andalso Char/=?QUOTE -> %% TODO: define character class restriction
	Ret1=fun(Uri)->
				 Ret(#tlit{lexeme=Lex,type=Uri})
		 end,
	#puri_state{parent=Ret1,buff=#puri{prefix=[Char],frag=nil}};
	
%% Bad State Trapper
push(S,Char) ->
	throw({bad_state_for_char,[Char],S}).
flush(S) ->
	S.
close(#m_state{ctx=_,parent=_,triple=_,next_pipe=NextPipeState}) ->
	ok=pipe:close(NextPipeState);
close(#skip_comment{parent=Ret}) ->
	ok=close(Ret(?EOF));
close(#skip_state{parent=Ret}) ->
	ok=close(Ret(?EOF));
close(S)->
	throw({unexpected_close,S}).

triple_finish(S=#m_state{parent=_,ctx=[finish_triple],triple=Trp,next_pipe=NextPipeState},?DOT)->
	NextPipeState1=pipe:push(NextPipeState,Trp),
	S#m_state{ctx=[subj],triple=#triple{},next_pipe=NextPipeState1};
triple_finish(S=#m_state{parent=_,ctx=[finish_triple],triple=Trp,next_pipe=NextPipeState},?COMMA)->
	NextPipeState1=pipe:push(NextPipeState,Trp),
	S#m_state{ctx=[obj],triple=Trp#triple{o=nil},next_pipe=NextPipeState1};
triple_finish(S=#m_state{parent=_,ctx=[finish_triple],triple=Trp,next_pipe=NextPipeState},?SEMI_COLON)->
	NextPipeState1=pipe:push(NextPipeState,Trp),
	S#m_state{ctx=[pred],triple=Trp#triple{p=nil,o=nil},next_pipe=NextPipeState1};
triple_finish(#m_state{parent=Ret,ctx=[finish_triple],triple=Trp,next_pipe=NextPipeState},?SQ_KET)->
	NextPipeState1=pipe:push(NextPipeState,Trp),
	Ret(NextPipeState1).

next_node(subj)->
	pred;
next_node(pred)->
	obj;
next_node(obj)->
	dot.

%------------------------------------------------------------
% Local Functions
%------------------------------------------------------------
test()->
%% 	Data="  <http://www.host.com#subj> <http://www.host.com#pred> <http://www.host.com#obj>, <mmmm>; <pred1> <obj1> .",
%% 	Data="  foaf:subj0 <http://www.host.com#pred> <http://www.host.com#obj> .",
%% 	Data="  foaf:subj0 <http://www.host.com#pred> 0.9,5,.4,-6,9e10; onto:charge -5.21e-20 .",
	 	Data="  foaf:subj0 <http://www.host.com#pred> [ onto:charge \"asdfasdf\"^^xsd:anyURI\n] .",
%% 	Data="  foaf:subj0 <http://www.host.com#pred> <kkkk1>,<kkkk> .",
%% 	Data="  foaf:subj0 <http://www.host.com#pred> <kkkk1>; <http://www.host.com#pred1> <kkkk> . foaf:subj1 <http://www.host.com#pred2> <kkkk2>.",
%% 	Data="  foaf:subj0 <http://www.host.com#pred> \"alfa romeo \\\" ZXC \" .",
%% 	Data="  foaf:subj0 <http://www.host.com#pred> \"alfa romeo \\\" ZXC \"^^<http://type> .",
%%  	Data="  foaf:subj0 <http://www.host.com#pred> \"alfa romeo \\\" ZXC \"^^xsd:string .",
%%   	Data="  foaf:subj0 <http://www.host.com#pred> \"alfa romeo \\\" ZXC \"@ru .",
%% Data="  foaf:subj0 <http://www.host.com#pred> \"\"\"ABC \\nDFG\"\"\"^^xsd:string .",
%% 	Data=" \t#dfsgsfd fdsdf\n @prefix onto: <http://www.w3.org/ontologies#> . foaf:subj0 <http://www.host.com#pred> [ <nested_pred> <nested_obj>,<nested_obj0>; <nested_pred10> [ <nested_nested_pred> <nn_obj> ] ] .",
%% 	Data="  foaf:subj0 <http://www.host.com#pred> [ <nested_pred> <nested_obj>,<nested_obj0>; <nested_pred10> <nested_obj10>,<nested_obj100> ] .",
%% 	Data="  foaf:subj0 <http://www.host.com#pred> [ <nested_pred> <nested_obj>,<nested_obj0>; <nested_pred10> [ <nested_nested_pred> <nn_obj> ] ] .",

	Iter=iter:from_list(Data),
	Pipe=pipe_tracer:new(new(pipe_console:new()),
						 pipe:trivial_consumer(
						   fun({I,{_,S}})->
								   io:format("~p -> ~p~n", [[I],S])
						   end)),
%% 	Pipe=new(pipe_console:new()),
	Pump=pump:new(Iter, Pipe),
	pump:init(Pump).

test(Filepath)->
	Iter=iter_counter:new_progress_observer(
		iter_fchars:new(Filepath, utf8),50000,
		fun(Note,Cnt)->
				io:format("!!!!!!! ~p[~p] ~p~n",[Note,now(),Cnt])
		end),
%% 	Iter=iter_fchars:new(Filepath, utf8),
	Pipe=new(pipe_console:new()),
%% 	Pipe=new(pipe:terminator()),
%% 	Pipe=pipe_tracer:new(new(pipe_console:new()),
%% 						 pipe:trivial_consumer(
%% 						   fun({I,{_,S}})->
%% 								   io:format("~p -> ~p~n", [[I],S])
%% 						   end)),
	Pump=pump:new(Iter, Pipe),
	pump:init(Pump).